package com.awei.project.service.impl;

import com.awei.project.common.ErrorCode;
import com.awei.project.exception.BusinessException;
import com.awei.project.model.dto.teamRequest.*;
import com.awei.project.model.entity.Team;
import com.awei.project.model.entity.User;
import com.awei.project.model.entity.UserTeam;
import com.awei.project.model.enums.TeamStatusEnum;
import com.awei.project.model.vo.TeamUserVo;
import com.awei.project.model.vo.UserVO;
import com.awei.project.service.UserService;
import com.awei.project.service.UserTeamService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.awei.project.service.TeamService;
import com.awei.project.mapper.TeamMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author gmh
 */
@Service
//高聚低耦
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
        implements TeamService {

        @Resource
        UserTeamService userTeamService;
        @Resource
        UserService userService;
        @Resource
        private RedissonClient redissonClient;

        @Override
        @Transactional(rollbackFor = Exception.class)
        public Long addTeam(TeamAddRequest teamAddRequest, User loginUser) {
                Team team = new Team();
                //校验是否为空请求参数是否为空
                if (teamAddRequest == null) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR);
                }
                Integer maxNum = teamAddRequest.getMaxNum();
                team.setMaxNum(maxNum);
                //1 队伍人数>=1且<=5
                if (maxNum < 0 || maxNum > 10) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数1至5人");
                }
                String name = teamAddRequest.getName();
                team.setName(name);
                int len = name.length();
                //2 队伍标题<=20
                if (len <= 0 || len > 20) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍名称至多20字");
                }
                String description = teamAddRequest.getDescription();
                team.setDescription(description);
                int desLen = description.length();
                //3 描述<=512
                if (desLen <= 0 || desLen > 512) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍名称至多512字");
                }
                Integer status = teamAddRequest.getStatus();
                if (TeamStatusEnum.getValues(status) == null) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍状态错误");
                }
                team.setStatus(status);
                //todo  4 status是否公开(int)默认0(公开)  1加密，  2 私密

                // 5如果status是加密状态，密码长度<=20
                String password = teamAddRequest.getPassword();
                if (TeamStatusEnum.getValues(status).equals(TeamStatusEnum.PASSWORD_TEAM) && (StringUtils.isBlank(password) || password.length() > 20)) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍密码输入错误");
                }
                team.setPassword(password);
                //2.1 过期时间-现在时间>1min
                Calendar currentCal = Calendar.getInstance();
                currentCal.add(Calendar.SECOND, 60);
                Date futureTime = currentCal.getTime();
                Date expireTime = teamAddRequest.getExpireTime();
                if (expireTime == null || expireTime.before(futureTime)) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍存活时间>1min");
                }
                team.setExpireTime(expireTime);
                //select count(*) from userTeam t where id=t.userid
                Long userId = loginUser.getId();
                team.setUserId(userId);
                QueryWrapper<Team> qw = new QueryWrapper<>();
                qw.eq("userid", userId);
                qw.and(qw1 -> qw1.gt("expireTime", new Date()).or().isNull("expireTime"));
                long count = this.count(qw);
                //2.2 校验用户最多创建10队伍
                if (count > 10) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍创建个数已达上限(10个)");
                }
                //2.3 插入队伍信息到队伍列表
                boolean save = this.save(team);
                if (!save) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR);
                }
                Long teamId = team.getId();
                //2.4 插入用户的队伍关系到队伍关系列表
                UserTeam userTeam = new UserTeam();
                userTeam.setUserId(userId);
                userTeam.setTeamId(teamId);
                userTeamService.save(userTeam);
                return teamId;
        }

        /**
         * 搜索队伍 (非管理员或创建者无法查询私密队伍)
         *
         */
        @Override//listTeam
        public List<TeamUserVo> listOtherOrMyTeam(TeamSearchRequest teamQuery, boolean isAdmin, HttpServletRequest request) {
                QueryWrapper<Team> queryWrapper = new QueryWrapper<>();
                // 组合查询条件
                if (teamQuery == null) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR);
                }
                Long id = teamQuery.getId();
                if (id != null && id > 0) {
                        queryWrapper.eq("id", id);
                }
                List<Long> idList = teamQuery.getIdList();
                if (!CollectionUtils.isEmpty(idList)) {
                        queryWrapper.in("id", idList);
                }
                String searchText = teamQuery.getSearchText();
                if (StringUtils.isNotBlank(searchText)) {
                        queryWrapper.and(qw -> qw.like("name", searchText).or().like("description", searchText));
                }
                String name = teamQuery.getName();
                if (StringUtils.isNotBlank(name)) {
                        queryWrapper.like("name", name);
                }
                String description = teamQuery.getDescription();
                if (StringUtils.isNotBlank(description)) {
                        queryWrapper.like("description", description);
                }
                Integer maxNum = teamQuery.getMaxNum();
                // 查询最大人数相等的
                if (maxNum != null && maxNum > 0) {
                        queryWrapper.eq("maxNum", maxNum);
                }
                Long userId = teamQuery.getUserId();
                // 根据创建人来查询
                if (userId != null && userId > 0) {
                        queryWrapper.eq("userId", userId);
                }
                // 根据状态来查询
                Integer status = teamQuery.getStatus();
                TeamStatusEnum statusEnum = TeamStatusEnum.getValues(status);
                if (statusEnum == null) {
                        statusEnum = TeamStatusEnum.PUBLIC_TEAM;
                }
                if (!isAdmin && statusEnum.equals(TeamStatusEnum.PRIVATE_TEAM)) {
                        throw new BusinessException(ErrorCode.NO_AUTH_ERROR);
                }
                if (!isAdmin) {//是否仅搜索相同状态的队伍
                        queryWrapper.eq("status", statusEnum.getValue());
                }
                // 不展示已过期的队伍
                // expireTime is null or expireTime > now()
                queryWrapper.and(qw -> qw.gt("expireTime", new Date()).or().isNull("expireTime"));
                List<Team> teamList = this.list(queryWrapper);
                if (CollectionUtils.isEmpty(teamList)) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "没有此数据");
                }
                List<TeamUserVo> teamUserVOList = new ArrayList<>();
                QueryWrapper<UserTeam> qw;
                // 关联查询创建人的用户信息
                for (Team team : teamList) {
                        qw= new QueryWrapper<>();
                        Long userId1 = team.getUserId();
                        Long teamId = team.getId();
                        qw.eq("teamId", teamId);
                        Integer count = Math.toIntExact(userTeamService.count(qw));
                        if (userId1 == null) {
                                continue;
                        }
                        User user = userService.getById(userId1);
                        TeamUserVo teamUserVO = new TeamUserVo();
                        BeanUtils.copyProperties(team, teamUserVO);
                        // 脱敏用户信息
                        if (user != null) {
                                UserVO userVO = new UserVO();
                                BeanUtils.copyProperties(user, userVO);
                                teamUserVO.setCreateUser(userVO);
                                teamUserVO.setHasJoinNum(count);
                        }
                        teamUserVOList.add(teamUserVO);
                }

                return teamUserVOList;
        }

        @Override
        @Transactional(rollbackFor = Exception.class)
        public List<User> listJoinUsers(Long id) {
                if (id == null || id < 0) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR);
                }
                List<User> users = baseMapper.selectJoinUsers(id);
                return users.stream().map(user -> userService.getSafetyUser(user)).collect(Collectors.toList());
        }

        /**
         * 搜索队伍
         */
        @Override
        public List<TeamUserVo> searchTeam(TeamSearchRequest teamQuery, boolean isAdmin, HttpServletRequest request) {
                List<TeamUserVo> teamList = this.listOtherOrMyTeam(teamQuery, isAdmin, request);
                final List<Long> teamIdList = teamList.stream().map(TeamUserVo::getId).collect(Collectors.toList());
                // 2、判断当前用户是否已加入队伍
                QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();
                try {
                        User loginUser = userService.getLoginUser(request);
                        userTeamQueryWrapper.eq("userId", loginUser.getId());
                        userTeamQueryWrapper.in("teamId", teamIdList);
                        List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);
                        // 已加入的队伍 id 集合
                        Set<Long> hasJoinTeamIdSet = userTeamList.stream().map(UserTeam::getTeamId).collect(Collectors.toSet());
                        teamList.forEach(team -> {
                                boolean hasJoin = hasJoinTeamIdSet.contains(team.getId());
                                team.setHasJoin(hasJoin);
                        });
                } catch (Exception e) {
                }
                // 3、查询已加入队伍的人数
                QueryWrapper<UserTeam> userTeamJoinQueryWrapper = new QueryWrapper<>();
                userTeamJoinQueryWrapper.in("teamId", teamIdList);
                List<UserTeam> userTeamList = userTeamService.list(userTeamJoinQueryWrapper);
                // 根据队伍 id =>  获取加入这个队伍的用户列表
                Map<Long, List<UserTeam>> teamIdUserTeamList = userTeamList.stream().collect(Collectors.groupingBy(UserTeam::getTeamId));
                teamList.forEach(team -> team.setHasJoinNum(teamIdUserTeamList.getOrDefault(team.getId(), new ArrayList<>()).size()));
                return teamList;
        }


        @Override
        public boolean updateTeam(TeamUpdateRequest teamUpdateRequest, User loginUser) {
                if (teamUpdateRequest == null) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "没有请求参数");
                }
                Long id = teamUpdateRequest.getId();
                if (id == null || id < 0) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍id错误");
                }
                //1 查询队伍是否存在
                Team oldTeam = this.getById(id);
                if (oldTeam == null) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍不存在");
                }
                //2 仅管理员或者队伍的创建者可修改
                Long userId = loginUser.getId();
                Long userId1 = oldTeam.getUserId();
                if (!(userService.isAdmin(loginUser) || userId.equals(userId1))) {
                        throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "您非队伍队长");
                }
                //4 状态判断，改为加密，必须加密码
                Integer status = teamUpdateRequest.getStatus();
                TeamStatusEnum values = TeamStatusEnum.getValues(status);
                if (TeamStatusEnum.PASSWORD_TEAM.equals(values)) {
                        String password = teamUpdateRequest.getPassword();
                        String password1 = oldTeam.getPassword();
                        if (password == null || password.equals(password1)) {
                                throw new BusinessException(ErrorCode.OPERATION_ERROR, "密码错误");
                        }
                }
                //3 若修改的新值和老值一致，则不修改
                Team team = new Team();
                BeanUtils.copyProperties(teamUpdateRequest, team);
                return this.updateById(team);
        }

        @Override
        public boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {
                if (teamJoinRequest == null) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR);
                }
                Long id = teamJoinRequest.getTeamId();
                if (id == null || id < 0) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍id错误");
                }
                Team team = getTeamById(id);
                //2  队伍存在，未满，未过期，公开的队伍。队伍加密，需要密码匹配，私有队伍禁止加入
                Integer status = team.getStatus();
                String password = teamJoinRequest.getPassword();
                if (TeamStatusEnum.getValues(status).equals(TeamStatusEnum.PASSWORD_TEAM) && StringUtils.isNotBlank(password)) {
                        if (!password.equals(team.getPassword())) {
                                throw new BusinessException(ErrorCode.OPERATION_ERROR, "密码错误");
                        }
                }
                if (TeamStatusEnum.getValues(status).equals(TeamStatusEnum.PRIVATE_TEAM)) {
                        throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "禁止加入私有队伍");
                }
                Date expireTime = team.getExpireTime();
                boolean before = expireTime.before(new Date());
                if (before) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍已过期");
                }
                Long userId = loginUser.getId();
                // 只有一个线程能获取到锁,加上线程锁
                RLock lock = redissonClient.getLock("aWei:join_team");
                try {
                        // 抢到锁并执行
                        while (true) {
                                if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {
                                        System.out.println("getLock: " + Thread.currentThread().getId());
                                        QueryWrapper<Team> qw = new QueryWrapper<>();
                                        qw.eq("userId", userId);
                                        qw.and(q -> q.gt("expireTime", new Date()).or().isNull("expireTime"));
                                        //查询数据库
                                        long count = this.count(qw);
                                        if (count > 10) {
                                                throw new BusinessException(ErrorCode.OPERATION_ERROR, "最多加入10个队伍");
                                        }
                                        //3  不能重复加入队伍
                                        QueryWrapper<UserTeam> qw2 = new QueryWrapper<>();
                                        Long teamId = team.getId();
                                        qw2.eq("userId", userId);
                                        qw2.eq("teamId", teamId);
                                        long UserReplaceJoinCount = userTeamService.count(qw2);
                                        if (UserReplaceJoinCount > 0) {
                                                throw new BusinessException(ErrorCode.OPERATION_ERROR, "禁止重复加入队伍");
                                        }
                                        //  添加用户队伍表信息，补充人数
                                        UserTeam userTeam = new UserTeam();
                                        userTeam.setUserId(userId);
                                        userTeam.setTeamId(teamId);
                                        boolean update = userTeamService.save(userTeam);
                                        if (!update) {
                                                throw new BusinessException(ErrorCode.OPERATION_ERROR);
                                        }
                                        return true;
                                }
                        }
                } catch (InterruptedException e) {
                        log.error("doCacheRecommendUser error", e);
                        return false;
                } finally {
                        // 只能释放自己的锁
                        if (lock.isHeldByCurrentThread()) {
                                System.out.println("unLock: " + Thread.currentThread().getId());
                                lock.unlock();
                        }
                }
        }

        @Override
        @Transactional(rollbackFor = Exception.class)
        public boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {
                Long teamId = teamQuitRequest.getTeamId();
                Long userId = loginUser.getId();
                // 1 队伍是否存在
                Team team = getTeamById(teamId);
                QueryWrapper<UserTeam> qw = new QueryWrapper<>();
                qw.eq("teamId", teamId);
                long TeamCount = userTeamService.count(qw);
                // 1 校验用户是否加入过该队伍
                qw.eq("userId", userId);
                long UserCount = userTeamService.count(qw);
                if (UserCount == 0) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "未加入该队伍");
                }
                // 2 若队伍仅为一人，队伍直接解散
                if (TeamCount == 1) {
                        this.removeById(teamId);
                } else {
                        Long teamUserId = team.getUserId();
                        if (teamUserId.equals(userId)) {
                                //  2 用户是否为队长：
                                //          队长：队长职位转移给队员(按加入的时间先后),退出组队
                                //按照加入顺序查询：last("ORDER BY id DESC LIMIT 20")
                                QueryWrapper<UserTeam> teamQw = new QueryWrapper<>();
                                teamQw.eq("teamId", teamId);
                                teamQw.last("order by id acs limit 2");
                                List<UserTeam> list = userTeamService.list(teamQw);
                                if (CollectionUtils.isEmpty(list) || list.size() < 2) {
                                        throw new BusinessException(ErrorCode.SYSTEM_ERROR);
                                }
                                UserTeam userTeam = list.get(1);
                                Long becomeUserId = userTeam.getUserId();
                                Team updateTeam = new Team();
                                updateTeam.setUserId(becomeUserId);
                                updateTeam.setId(teamId);
                                boolean b = this.updateById(updateTeam);
                                if (!b) {
                                        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "更新队伍队长失败");
                                }
                        }
                }
                //关系表删除         非队长：直接退出
                boolean remove = userTeamService.remove(qw);
                if (!remove) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "关系删除失败");
                }
                return true;
        }

        @Override
        @Transactional(rollbackFor = Exception.class)
        public boolean deleteTeam(long id, User loginUser) {
                //检验队伍是否存在
                Team team = getTeamById(id);
                Long teamId = team.getId();
                //  校验队伍是否为队长
                Long teamUserIdId = team.getUserId();
                Long userId = loginUser.getId();
                if (!teamUserIdId.equals(userId)) {
                        throw new BusinessException(ErrorCode.NO_AUTH_ERROR, "队长可解散队伍");
                }
                //移除所有加入队伍的关联信息：队伍信息
                QueryWrapper<UserTeam> qw = new QueryWrapper<>();
                qw.eq("teamId", teamId);
                boolean remove = userTeamService.remove(qw);
                if (!remove) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍关系删除失败");
                }
                //  删除队伍
                boolean b = this.removeById(teamId);
                if (!b) {
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "队伍删除失败");
                }
                return true;
        }


        //加个查询队伍的全体队员

        private Team getTeamById(Long teamId) {
                if (teamId == null || teamId <= 0) {
                        throw new BusinessException(ErrorCode.PARAMS_ERROR);
                }
                Team team = this.getById(teamId);
                if (team == null) {
                        throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在");
                }
                return team;
        }

}




